using CollabApp.Application.Interfaces;
using CollabApp.Domain.Entities.Game;
using CollabApp.Domain.Services.Game;
using Microsoft.Extensions.Logging;
using System.Numerics;

namespace CollabApp.Application.Services.Game;

/// <summary>
/// 碰撞检测服务实现
/// 负责处理圈地游戏中的各种碰撞检测逻辑，包括轨迹碰撞、边界检测、道具拾取等
/// 采用高精度算法确保检测准确性，支持并发处理提升性能
/// </summary>
public class CollisionDetectionService : ICollisionDetectionService
{
    private readonly ILogger<CollisionDetectionService> _logger;
    private readonly IRedisService _redisService;

    public CollisionDetectionService(
        ILogger<CollisionDetectionService> logger,
        IRedisService redisService)
    {
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        _redisService = redisService ?? throw new ArgumentNullException(nameof(redisService));
    }

    /// <summary>
    /// 检测轨迹截断碰撞
    /// 使用线段相交算法检测玩家移动路径是否与其他玩家轨迹相交
    /// 这是游戏中最核心的死亡判定逻辑
    /// </summary>
    /// <param name="gameId">游戏标识</param>
    /// <param name="playerId">移动的玩家标识</param>
    /// <param name="fromPosition">移动起始位置</param>
    /// <param name="toPosition">移动目标位置</param>
    /// <param name="isDrawing">该玩家是否正在画线</param>
    /// <returns>轨迹碰撞检测结果</returns>
    public async Task<TrailCollisionResult> CheckTrailCollisionAsync(
        Guid gameId, 
        Guid playerId, 
        Position fromPosition, 
        Position toPosition, 
        bool isDrawing)
    {
        try
        {
            _logger.LogDebug("开始检测玩家 {PlayerId} 的轨迹碰撞，从 ({FromX},{FromY}) 到 ({ToX},{ToY})", 
                playerId, fromPosition.X, fromPosition.Y, toPosition.X, toPosition.Y);

            var result = new TrailCollisionResult();
            
            // 获取游戏状态数据
            var gameStateKey = $"game:{gameId}:state";
            var gameState = await _redisService.GetHashAllAsync(gameStateKey);
            
            if (!gameState.Any())
            {
                _logger.LogWarning("游戏 {GameId} 状态不存在", gameId);
                return result;
            }

            // 获取当前玩家状态
            var playerStateKey = $"game:{gameId}:player:{playerId}";
            var playerState = await _redisService.GetHashAllAsync(playerStateKey);
            
            // 检查玩家是否有护盾或幽灵状态
            bool hasShield = playerState.ContainsKey("shield_active") && 
                            bool.Parse(playerState["shield_active"]);
            bool hasGhost = playerState.ContainsKey("ghost_active") && 
                           bool.Parse(playerState["ghost_active"]);

            // 获取所有其他玩家的轨迹数据
            var playersKey = $"game:{gameId}:players";
            var allPlayers = await _redisService.GetSetMembersAsync(playersKey);
            
            foreach (var otherPlayerIdStr in allPlayers)
            {
                if (!Guid.TryParse(otherPlayerIdStr, out var otherPlayerId) || otherPlayerId == playerId)
                    continue;

                // 检查与其他玩家轨迹的碰撞
                var collisionPoint = await CheckLineSegmentCollisionAsync(gameId, playerId, otherPlayerId, 
                    fromPosition, toPosition, isDrawing);
                
                if (collisionPoint != null)
                {
                    result.HasCollision = true;
                    result.CollidedWithPlayerId = otherPlayerId;
                    result.CollisionPoint = collisionPoint;
                    
                    // 判断碰撞是否致命
                    if (hasGhost)
                    {
                        result.CanPassThrough = true;
                        result.IsDeadly = false;
                        _logger.LogDebug("玩家 {PlayerId} 处于幽灵状态，可以穿越轨迹", playerId);
                    }
                    else if (hasShield && isDrawing)
                    {
                        result.ShieldBlocked = true;
                        result.IsDeadly = false;
                        _logger.LogDebug("玩家 {PlayerId} 护盾阻挡了致命碰撞", playerId);
                        
                        // 消耗护盾
                        await _redisService.HashDeleteAsync(playerStateKey, "shield_active");
                    }
                    else if (isDrawing)
                    {
                        result.IsDeadly = true;
                        result.CollisionType = "Trail";
                        _logger.LogDebug("玩家 {PlayerId} 轨迹被截断，导致死亡", playerId);
                    }
                    
                    break;
                }
            }

            // 检查与自己轨迹的碰撞（自杀检测）
            if (!result.HasCollision && isDrawing)
            {
                var selfCollisionPoint = await CheckSelfTrailCollisionAsync(gameId, playerId, fromPosition, toPosition);
                if (selfCollisionPoint != null)
                {
                    result.HasCollision = true;
                    result.CollidedWithPlayerId = playerId;
                    result.CollisionPoint = selfCollisionPoint;
                    result.IsDeadly = true;
                    result.CollisionType = "SelfTrail";
                    _logger.LogDebug("玩家 {PlayerId} 与自己的轨迹碰撞", playerId);
                }
            }

            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "检测轨迹碰撞时发生错误，GameId: {GameId}, PlayerId: {PlayerId}", gameId, playerId);
            return new TrailCollisionResult();
        }
    }

    /// <summary>
    /// 检测两条线段是否相交的核心算法
    /// 使用向量叉积判断线段相交关系
    /// </summary>
    private async Task<Position?> CheckLineSegmentCollisionAsync(
        Guid gameId, Guid currentPlayerId, Guid otherPlayerId,
        Position fromPos, Position toPos, bool isDrawing)
    {
        try
        {
            // 获取其他玩家的当前轨迹
            var otherTrailKey = $"game:{gameId}:player:{otherPlayerId}:trail";
            var otherTrailData = await _redisService.ListRangeAsync(otherTrailKey);
            
            if (otherTrailData.Count < 2) return null;

            // 将轨迹数据转换为位置点
            var otherTrail = new List<Position>();
            foreach (var pointData in otherTrailData)
            {
                var parts = pointData.Split(',');
                if (parts.Length >= 2 && 
                    float.TryParse(parts[0], out float x) && 
                    float.TryParse(parts[1], out float y))
                {
                    otherTrail.Add(new Position { X = x, Y = y });
                }
            }

            // 检查当前移动线段与其他玩家轨迹的每个线段是否相交
            for (int i = 0; i < otherTrail.Count - 1; i++)
            {
                var trailStart = otherTrail[i];
                var trailEnd = otherTrail[i + 1];
                
                var intersectionPoint = GetLineSegmentIntersection(
                    fromPos, toPos, trailStart, trailEnd);
                
                if (intersectionPoint != null)
                {
                    return intersectionPoint;
                }
            }

            return null;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "检查线段碰撞时发生错误");
            return null;
        }
    }

    /// <summary>
    /// 计算两条线段的交点
    /// 使用参数方程和线性代数方法计算交点
    /// </summary>
    private Position? GetLineSegmentIntersection(Position p1, Position p2, Position p3, Position p4)
    {
        var denominator = (p1.X - p2.X) * (p3.Y - p4.Y) - (p1.Y - p2.Y) * (p3.X - p4.X);
        
        // 平行线检测
        if (Math.Abs(denominator) < 1e-10) return null;
        
        var t = ((p1.X - p3.X) * (p3.Y - p4.Y) - (p1.Y - p3.Y) * (p3.X - p4.X)) / denominator;
        var u = -((p1.X - p2.X) * (p1.Y - p3.Y) - (p1.Y - p2.Y) * (p1.X - p3.X)) / denominator;
        
        // 检查交点是否在两条线段上
        if (t >= 0 && t <= 1 && u >= 0 && u <= 1)
        {
            return new Position
            {
                X = p1.X + t * (p2.X - p1.X),
                Y = p1.Y + t * (p2.Y - p1.Y)
            };
        }
        
        return null;
    }

    /// <summary>
    /// 检测与自己轨迹的碰撞（自杀检测）
    /// </summary>
    private async Task<Position?> CheckSelfTrailCollisionAsync(
        Guid gameId, Guid playerId, Position fromPos, Position toPos)
    {
        try
        {
            var trailKey = $"game:{gameId}:player:{playerId}:trail";
            var trailData = await _redisService.ListRangeAsync(trailKey);
            
            if (trailData.Count < 4) return null; // 至少需要2个线段才可能自相交

            var trail = new List<Position>();
            foreach (var pointData in trailData.Take(trailData.Count - 1)) // 排除最后一个点避免相邻检测
            {
                var parts = pointData.Split(',');
                if (parts.Length >= 2 && 
                    float.TryParse(parts[0], out float x) && 
                    float.TryParse(parts[1], out float y))
                {
                    trail.Add(new Position { X = x, Y = y });
                }
            }

            // 检查当前移动与历史轨迹的交点（排除相邻线段）
            for (int i = 0; i < trail.Count - 3; i++)
            {
                var intersectionPoint = GetLineSegmentIntersection(
                    fromPos, toPos, trail[i], trail[i + 1]);
                
                if (intersectionPoint != null)
                {
                    return intersectionPoint;
                }
            }

            return null;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "检查自我轨迹碰撞时发生错误");
            return null;
        }
    }

    /// <summary>
    /// 检测地图边界碰撞
    /// 检查玩家移动是否超出圆形地图边界
    /// </summary>
    /// <param name="gameId">游戏标识</param>
    /// <param name="position">要检测的位置</param>
    /// <returns>边界碰撞结果</returns>
    public async Task<BoundaryCollisionResult> CheckMapBoundaryAsync(Guid gameId, Position position)
    {
        try
        {
            _logger.LogDebug("检测地图边界碰撞，位置: ({X},{Y})", position.X, position.Y);

            var result = new BoundaryCollisionResult();

            // 获取地图配置
            var gameConfigKey = $"game:{gameId}:config";
            var gameConfig = await _redisService.GetHashAllAsync(gameConfigKey);

            if (!gameConfig.Any())
            {
                _logger.LogWarning("游戏 {GameId} 配置不存在", gameId);
                return result;
            }

            // 获取地图大小和中心点
            var mapWidth = float.Parse(gameConfig.GetValueOrDefault("map_width", "1000"));
            var mapHeight = float.Parse(gameConfig.GetValueOrDefault("map_height", "1000"));
            var mapRadius = Math.Min(mapWidth, mapHeight) / 2f;
            var centerX = mapWidth / 2f;
            var centerY = mapHeight / 2f;

            // 计算距离地图中心的距离
            var distanceFromCenter = (float)Math.Sqrt(
                Math.Pow(position.X - centerX, 2) + Math.Pow(position.Y - centerY, 2));

            result.DistanceFromCenter = distanceFromCenter;
            result.MapRadius = mapRadius;
            result.BoundaryType = "Circle";

            // 检查是否超出边界
            if (distanceFromCenter > mapRadius)
            {
                result.IsOutOfBounds = true;
                
                // 计算修正后的有效位置（投影到边界上）
                var angle = Math.Atan2(position.Y - centerY, position.X - centerX);
                result.ValidPosition = new Position
                {
                    X = centerX + (float)(mapRadius * Math.Cos(angle)),
                    Y = centerY + (float)(mapRadius * Math.Sin(angle))
                };
                
                _logger.LogDebug("位置超出边界，原位置: ({X},{Y})，修正位置: ({ValidX},{ValidY})", 
                    position.X, position.Y, result.ValidPosition.X, result.ValidPosition.Y);
            }
            else
            {
                result.ValidPosition = position;
            }

            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "检测地图边界碰撞时发生错误，GameId: {GameId}", gameId);
            return new BoundaryCollisionResult { ValidPosition = position };
        }
    }

    /// <summary>
    /// 解析Redis中的障碍物数据为MapObstacle对象
    /// </summary>
    private MapObstacle? ParseMapObstacle(Guid obstacleId, Dictionary<string, string> obstacleData)
    {
        try
        {
            if (!obstacleData.ContainsKey("type")) return null;

            var obstacle = new MapObstacle
            {
                Id = obstacleId,
                ObstacleType = obstacleData["type"],
                IsDestructible = obstacleData.GetValueOrDefault("destructible", "false") == "true"
            };

            // 解析中心点
            if (obstacleData.ContainsKey("center_x") && obstacleData.ContainsKey("center_y"))
            {
                obstacle.Center = new Position
                {
                    X = float.Parse(obstacleData["center_x"]),
                    Y = float.Parse(obstacleData["center_y"])
                };
            }

            // 解析半径（圆形障碍物）
            if (obstacleData.ContainsKey("radius"))
            {
                obstacle.Radius = float.Parse(obstacleData["radius"]);
            }

            // 解析边界点（多边形障碍物）
            if (obstacleData.ContainsKey("boundary"))
            {
                var boundaryStr = obstacleData["boundary"];
                var points = boundaryStr.Split(';');
                
                foreach (var pointStr in points)
                {
                    var coords = pointStr.Split(',');
                    if (coords.Length >= 2 && 
                        float.TryParse(coords[0], out float x) && 
                        float.TryParse(coords[1], out float y))
                    {
                        obstacle.Boundary.Add(new Position { X = x, Y = y });
                    }
                }
            }

            return obstacle;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "解析障碍物数据时发生错误，ObstacleId: {ObstacleId}", obstacleId);
            return null;
        }
    }

    /// <summary>
    /// 检测线段与圆形的碰撞
    /// 使用精确的几何算法，考虑边界情况和数值精度
    /// </summary>
    private bool CheckLineCircleCollision(Position lineStart, Position lineEnd, Position circleCenter, float radius)
    {
        // 将坐标转换为相对于圆心的坐标系
        var relativeStart = new Vector2(lineStart.X - circleCenter.X, lineStart.Y - circleCenter.Y);
        var relativeEnd = new Vector2(lineEnd.X - circleCenter.X, lineEnd.Y - circleCenter.Y);
        
        // 检查端点是否在圆内
        if (relativeStart.LengthSquared() <= radius * radius || 
            relativeEnd.LengthSquared() <= radius * radius)
        {
            return true;
        }
        
        // 计算线段向量
        var lineVector = relativeEnd - relativeStart;
        var lineLength = lineVector.Length();
        
        if (lineLength < 1e-6f) // 线段长度几乎为0
        {
            return relativeStart.LengthSquared() <= radius * radius;
        }
        
        // 标准化线段向量
        var normalizedLine = lineVector / lineLength;
        
        // 计算圆心到线段起点的向量
        var toStart = -relativeStart;
        
        // 计算投影长度
        var projectionLength = Vector2.Dot(toStart, normalizedLine);
        
        // 限制投影在线段范围内
        projectionLength = Math.Max(0, Math.Min(lineLength, projectionLength));
        
        // 计算线段上最近点
        var closestPoint = relativeStart + normalizedLine * projectionLength;
        
        // 检查最近点到圆心的距离
        var distanceSquared = closestPoint.LengthSquared();
        var radiusSquared = radius * radius;
        
        return distanceSquared <= radiusSquared;
    }

    /// <summary>
    /// 检测线段与多边形的碰撞
    /// 检查线段是否与多边形的任何边相交
    /// </summary>
    private bool CheckLinePolygonCollision(Position lineStart, Position lineEnd, List<Position> polygon)
    {
        if (polygon.Count < 3) return false;

        // 检查线段与多边形每条边是否相交
        for (int i = 0; i < polygon.Count; i++)
        {
            var polyStart = polygon[i];
            var polyEnd = polygon[(i + 1) % polygon.Count];
            
            if (GetLineSegmentIntersection(lineStart, lineEnd, polyStart, polyEnd) != null)
            {
                return true;
            }
        }

        return false;
    }

    /// <summary>
    /// 计算绕过障碍物的有效位置
    /// 使用A*寻路算法的简化版本，找到绕过障碍物的最佳路径
    /// </summary>
    private Position CalculateValidPositionAroundObstacles(Position fromPosition, Position toPosition, List<MapObstacle> obstacles)
    {
        // 如果没有障碍物，直接返回目标位置
        if (!obstacles.Any()) return toPosition;

        // 尝试多个避障方向
        var avoidanceDirections = new[]
        {
            new Vector2(0, 1),    // 上
            new Vector2(0, -1),   // 下
            new Vector2(-1, 0),   // 左
            new Vector2(1, 0),    // 右
            new Vector2(-1, 1),   // 左上
            new Vector2(1, 1),    // 右上
            new Vector2(-1, -1),  // 左下
            new Vector2(1, -1)    // 右下
        };

        const float AVOIDANCE_STEP = 10f;
        const int MAX_ATTEMPTS = 8;

        // 尝试每个方向，找到第一个无碰撞的位置
        for (int attempt = 1; attempt <= MAX_ATTEMPTS; attempt++)
        {
            var stepSize = AVOIDANCE_STEP * attempt;
            
            foreach (var direction in avoidanceDirections)
            {
                var candidatePosition = new Position
                {
                    X = fromPosition.X + direction.X * stepSize,
                    Y = fromPosition.Y + direction.Y * stepSize
                };

                // 检查这个位置是否与所有障碍物都无碰撞
                bool hasCollision = false;
                foreach (var obstacle in obstacles)
                {
                    if (obstacle.ObstacleType == "Circular")
                    {
                        var distance = CalculateDistance(candidatePosition, obstacle.Center);
                        if (distance <= obstacle.Radius + 2f) // 额外2像素安全距离
                        {
                            hasCollision = true;
                            break;
                        }
                    }
                    else
                    {
                        if (IsPointInPolygon(candidatePosition, obstacle.Boundary))
                        {
                            hasCollision = true;
                            break;
                        }
                    }
                }

                if (!hasCollision)
                {
                    return candidatePosition;
                }
            }
        }

        // 如果所有方向都被阻挡，返回起始位置
        return fromPosition;
    }

    /// <summary>
    /// 解析Redis中的道具数据为PickupablePowerUp对象
    /// </summary>
    private PickupablePowerUp? ParsePickupablePowerUp(Guid powerUpId, Dictionary<string, string> powerUpData)
    {
        try
        {
            if (!powerUpData.ContainsKey("type") || !powerUpData.ContainsKey("position_x") || !powerUpData.ContainsKey("position_y"))
                return null;

            // 解析道具类型
            if (!Enum.TryParse<TerritoryGamePowerUpType>(powerUpData["type"], out var powerUpType))
                return null;

            var powerUp = new PickupablePowerUp
            {
                Id = powerUpId,
                Type = powerUpType,
                Position = new Position
                {
                    X = float.Parse(powerUpData["position_x"]),
                    Y = float.Parse(powerUpData["position_y"])
                },
                IsPickupable = powerUpData.GetValueOrDefault("status", "") == "active"
            };

            // 解析生成时间
            if (powerUpData.ContainsKey("spawn_time") && DateTime.TryParse(powerUpData["spawn_time"], out var spawnTime))
            {
                powerUp.SpawnTime = spawnTime;
            }

            return powerUp;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "解析道具数据时发生错误，PowerUpId: {PowerUpId}", powerUpId);
            return null;
        }
    }

    /// <summary>
    /// 计算两点之间的欧几里得距离
    /// </summary>
    private float CalculateDistance(Position pos1, Position pos2)
    {
        var dx = pos1.X - pos2.X;
        var dy = pos1.Y - pos2.Y;
        return (float)Math.Sqrt(dx * dx + dy * dy);
    }

    /// <summary>
    /// 检查位置的领地归属
    /// </summary>
    private async Task<TerritoryOwnershipInfo?> CheckPositionTerritoryOwnershipAsync(Guid gameId, Position position)
    {
        try
        {
            // 获取所有玩家的领地数据
            var playersKey = $"game:{gameId}:players";
            var allPlayers = await _redisService.GetSetMembersAsync(playersKey);

            foreach (var playerIdStr in allPlayers)
            {
                if (!Guid.TryParse(playerIdStr, out var ownerId))
                    continue;

                // 获取玩家领地边界
                var territoryKey = $"game:{gameId}:player:{ownerId}:territory";
                var territoryData = await _redisService.ListRangeAsync(territoryKey);

                if (territoryData.Count < 3) continue; // 至少需要3个点构成区域

                var territory = new List<Position>();
                foreach (var pointData in territoryData)
                {
                    var parts = pointData.Split(',');
                    if (parts.Length >= 2 && 
                        float.TryParse(parts[0], out float x) && 
                        float.TryParse(parts[1], out float y))
                    {
                        territory.Add(new Position { X = x, Y = y });
                    }
                }

                // 检查位置是否在这个玩家的领地内
                if (IsPointInPolygon(position, territory))
                {
                    return new TerritoryOwnershipInfo
                    {
                        OwnerId = ownerId,
                        IsOwned = true,
                        IsNeutralZone = false
                    };
                }
            }

            // 如果不在任何玩家领地内，则为中立区域
            return new TerritoryOwnershipInfo
            {
                OwnerId = null,
                IsOwned = false,
                IsNeutralZone = true
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "检查位置领地归属时发生错误");
            return null;
        }
    }

    /// <summary>
    /// 判断点是否在多边形内部
    /// 使用射线交点算法
    /// </summary>
    private bool IsPointInPolygon(Position point, List<Position> polygon)
    {
        if (polygon.Count < 3) return false;

        bool inside = false;
        int j = polygon.Count - 1;

        for (int i = 0; i < polygon.Count; i++)
        {
            var pi = polygon[i];
            var pj = polygon[j];

            if (((pi.Y > point.Y) != (pj.Y > point.Y)) &&
                (point.X < (pj.X - pi.X) * (point.Y - pi.Y) / (pj.Y - pi.Y) + pi.X))
            {
                inside = !inside;
            }
            j = i;
        }

        return inside;
    }

    /// <summary>
    /// 获取玩家名称
    /// </summary>
    private async Task<string?> GetPlayerNameAsync(Guid gameId, Guid playerId)
    {
        try
        {
            var playerKey = $"game:{gameId}:player:{playerId}:info";
            var playerInfo = await _redisService.GetHashAllAsync(playerKey);
            return playerInfo.GetValueOrDefault("name", playerId.ToString()[..8]);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取玩家名称时发生错误");
            return playerId.ToString()[..8];
        }
    }

    /// <summary>
    /// 确定领地转换类型
    /// </summary>
    private TerritoryTransitionType DetermineTransitionType(TerritoryOwnershipInfo? previous, TerritoryOwnershipInfo? current)
    {
        if (previous?.IsNeutralZone == true && current?.IsOwned == true)
            return TerritoryTransitionType.NeutralToOwned;
        
        if (previous?.IsOwned == true && current?.IsNeutralZone == true)
            return TerritoryTransitionType.OwnedToNeutral;
        
        if (previous?.IsOwned == true && current?.IsOwned == true && previous.OwnerId != current.OwnerId)
            return TerritoryTransitionType.OwnedToOtherOwned;
        
        return TerritoryTransitionType.NoChange;
    }

    /// <summary>
    /// 计算速度修正值
    /// 根据领地归属和转换类型计算移动速度修正
    /// </summary>
    private float CalculateSpeedModifier(Guid playerId, TerritoryOwnershipInfo? ownership, TerritoryTransitionType transitionType)
    {
        // 基础速度
        float modifier = 1.0f;

        if (ownership?.IsOwned == true)
        {
            if (ownership.OwnerId == playerId)
            {
                // 在自己领地内：速度提升15%
                modifier = 1.15f;
            }
            else
            {
                // 在敌方领地内：速度降低20%
                modifier = 0.8f;
            }
        }

        return modifier;
    }

    /// <summary>
    /// 领地归属信息内部类
    /// </summary>
    private class TerritoryOwnershipInfo
    {
        public Guid? OwnerId { get; set; }
        public bool IsOwned { get; set; }
        public bool IsNeutralZone { get; set; }
    }

    /// <summary>
    /// 计算点到线段的最短距离
    /// </summary>
    private float CalculatePointToLineSegmentDistance(Position point, Position lineStart, Position lineEnd)
    {
        // 线段向量
        var lineVector = new Vector2(lineEnd.X - lineStart.X, lineEnd.Y - lineStart.Y);
        var lineLength = lineVector.Length();
        
        if (lineLength == 0)
            return CalculateDistance(point, lineStart);

        // 点到线段起点的向量
        var pointVector = new Vector2(point.X - lineStart.X, point.Y - lineStart.Y);
        
        // 计算投影长度（标量投影）
        var projection = Vector2.Dot(pointVector, lineVector) / lineLength;
        
        // 限制投影在线段范围内
        projection = Math.Max(0, Math.Min(lineLength, projection));
        
        // 计算投影点
        var normalizedLineVector = lineVector / lineLength;
        var projectionPoint = new Vector2(lineStart.X, lineStart.Y) + normalizedLineVector * projection;
        
        // 计算距离
        return Vector2.Distance(new Vector2(point.X, point.Y), projectionPoint);
    }

    /// <summary>
    /// 找到线段上距离指定点最近的点
    /// </summary>
    private Position FindNearestPointOnLineSegment(Position point, Position lineStart, Position lineEnd)
    {
        var lineVector = new Vector2(lineEnd.X - lineStart.X, lineEnd.Y - lineStart.Y);
        var lineLength = lineVector.Length();
        
        if (lineLength == 0)
            return lineStart;

        var pointVector = new Vector2(point.X - lineStart.X, point.Y - lineStart.Y);
        var projection = Vector2.Dot(pointVector, lineVector) / lineLength;
        
        projection = Math.Max(0, Math.Min(lineLength, projection));
        
        var normalizedLineVector = lineVector / lineLength;
        var nearestPoint = new Vector2(lineStart.X, lineStart.Y) + normalizedLineVector * projection;
        
        return new Position { X = nearestPoint.X, Y = nearestPoint.Y };
    }

    /// <summary>
    /// 计算威胁等级
    /// </summary>
    private ThreatLevel CalculateThreatLevel(float distance, float warningDistance)
    {
        var ratio = distance / warningDistance;
        
        if (ratio <= 0.3f) return ThreatLevel.Critical;
        if (ratio <= 0.5f) return ThreatLevel.High;
        if (ratio <= 0.7f) return ThreatLevel.Medium;
        if (ratio <= 1.0f) return ThreatLevel.Low;
        
        return ThreatLevel.None;
    }

    // 其他方法将在后续逐步实现...
    
    /// <summary>
    /// 检测障碍物碰撞
    /// 检测玩家移动路径是否与地图中的固定障碍物或可破坏障碍物相交
    /// </summary>
    /// <param name="gameId">游戏标识</param>
    /// <param name="fromPosition">移动起始位置</param>
    /// <param name="toPosition">移动目标位置</param>
    /// <returns>障碍物碰撞结果</returns>
    public async Task<ObstacleCollisionResult> CheckObstacleCollisionAsync(Guid gameId, Position fromPosition, Position toPosition)
    {
        try
        {
            _logger.LogDebug("检测障碍物碰撞，从 ({FromX},{FromY}) 到 ({ToX},{ToY})", 
                fromPosition.X, fromPosition.Y, toPosition.X, toPosition.Y);

            var result = new ObstacleCollisionResult();

            // 获取地图障碍物配置
            var obstaclesKey = $"game:{gameId}:obstacles";
            var obstacleIds = await _redisService.GetSetMembersAsync(obstaclesKey);

            if (!obstacleIds.Any())
            {
                _logger.LogDebug("游戏 {GameId} 没有配置障碍物", gameId);
                result.ValidPosition = toPosition;
                return result;
            }

            var collidedObstacles = new List<MapObstacle>();

            foreach (var obstacleIdStr in obstacleIds)
            {
                if (!Guid.TryParse(obstacleIdStr, out var obstacleId))
                    continue;

                // 获取障碍物详细信息
                var obstacleKey = $"game:{gameId}:obstacle:{obstacleId}";
                var obstacleData = await _redisService.GetHashAllAsync(obstacleKey);

                if (!obstacleData.Any()) continue;

                var obstacle = ParseMapObstacle(obstacleId, obstacleData);
                if (obstacle == null) continue;

                // 检测与障碍物的碰撞
                bool hasCollision = false;

                if (obstacle.ObstacleType == "Circular")
                {
                    // 圆形障碍物碰撞检测
                    hasCollision = CheckLineCircleCollision(fromPosition, toPosition, obstacle.Center, obstacle.Radius);
                }
                else
                {
                    // 多边形障碍物碰撞检测
                    hasCollision = CheckLinePolygonCollision(fromPosition, toPosition, obstacle.Boundary);
                }

                if (hasCollision)
                {
                    result.HasCollision = true;
                    collidedObstacles.Add(obstacle);
                    
                    _logger.LogDebug("检测到与障碍物 {ObstacleId} 的碰撞，类型: {Type}", 
                        obstacleId, obstacle.ObstacleType);
                }
            }

            result.CollidedObstacles = collidedObstacles;

            // 如果有碰撞，计算有效的移动位置
            if (result.HasCollision)
            {
                result.ValidPosition = CalculateValidPositionAroundObstacles(fromPosition, toPosition, collidedObstacles);
                result.BlocksMovement = true;
            }
            else
            {
                result.ValidPosition = toPosition;
                result.BlocksMovement = false;
            }

            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "检测障碍物碰撞时发生错误，GameId: {GameId}", gameId);
            return new ObstacleCollisionResult { ValidPosition = toPosition };
        }
    }

    /// <summary>
    /// 检测道具拾取碰撞
    /// 检测玩家是否接近地图上的道具，支持自定义拾取半径
    /// </summary>
    /// <param name="gameId">游戏标识</param>
    /// <param name="playerId">玩家标识</param>
    /// <param name="playerPosition">玩家当前位置</param>
    /// <param name="pickupRadius">拾取范围，默认20像素</param>
    /// <returns>道具拾取碰撞结果</returns>
    public async Task<PowerUpPickupCollisionResult> CheckPowerUpPickupAsync(Guid gameId, Guid playerId, Position playerPosition, float pickupRadius = 20f)
    {
        try
        {
            _logger.LogDebug("检测道具拾取碰撞，玩家 {PlayerId}，位置: ({X},{Y})，半径: {Radius}", 
                playerId, playerPosition.X, playerPosition.Y, pickupRadius);

            var result = new PowerUpPickupCollisionResult();

            // 检查玩家是否已持有道具
            var playerStateKey = $"game:{gameId}:player:{playerId}";
            var playerState = await _redisService.GetHashAllAsync(playerStateKey);
            
            bool hasActivePowerUp = playerState.ContainsKey("active_powerup") && 
                                   !string.IsNullOrEmpty(playerState["active_powerup"]);

            if (hasActivePowerUp)
            {
                _logger.LogDebug("玩家 {PlayerId} 已持有道具，无法拾取新道具", playerId);
                return result;
            }

            // 获取地图上的所有道具
            var powerUpsKey = $"game:{gameId}:powerups";
            var powerUpIds = await _redisService.GetSetMembersAsync(powerUpsKey);

            if (!powerUpIds.Any())
            {
                _logger.LogDebug("游戏 {GameId} 地图上没有道具", gameId);
                return result;
            }

            var nearbyPowerUps = new List<PickupablePowerUp>();
            PickupablePowerUp? closestPowerUp = null;
            float closestDistance = float.MaxValue;

            foreach (var powerUpIdStr in powerUpIds)
            {
                if (!Guid.TryParse(powerUpIdStr, out var powerUpId))
                    continue;

                // 获取道具详细信息
                var powerUpKey = $"game:{gameId}:powerup:{powerUpId}";
                var powerUpData = await _redisService.GetHashAllAsync(powerUpKey);

                if (!powerUpData.Any() || powerUpData.GetValueOrDefault("status", "") != "active")
                    continue;

                var powerUp = ParsePickupablePowerUp(powerUpId, powerUpData);
                if (powerUp == null) continue;

                // 计算距离
                var distance = CalculateDistance(playerPosition, powerUp.Position);
                powerUp.DistanceFromPlayer = distance;

                // 检查是否在拾取范围内
                if (distance <= pickupRadius)
                {
                    powerUp.IsPickupable = true;
                    nearbyPowerUps.Add(powerUp);

                    // 记录最近的道具
                    if (distance < closestDistance)
                    {
                        closestDistance = distance;
                        closestPowerUp = powerUp;
                    }

                    _logger.LogDebug("检测到可拾取道具 {PowerUpId}，类型: {Type}，距离: {Distance}", 
                        powerUpId, powerUp.Type, distance);
                }
                else if (distance <= pickupRadius * 2) // 预警范围
                {
                    nearbyPowerUps.Add(powerUp);
                }
            }

            result.NearbyPowerUps = nearbyPowerUps;
            result.ClosestPowerUp = closestPowerUp;
            result.ClosestDistance = closestDistance;
            result.CanPickup = closestPowerUp != null;

            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "检测道具拾取碰撞时发生错误，GameId: {GameId}, PlayerId: {PlayerId}", gameId, playerId);
            return new PowerUpPickupCollisionResult();
        }
    }

    /// <summary>
    /// 检测领地进入/离开
    /// 检测玩家移动是否导致领地归属变化，用于触发速度修正和视觉效果
    /// </summary>
    /// <param name="gameId">游戏标识</param>
    /// <param name="playerId">移动的玩家标识</param>
    /// <param name="fromPosition">移动起始位置</param>
    /// <param name="toPosition">移动目标位置</param>
    /// <returns>领地转换结果</returns>
    public async Task<TerritoryTransitionResult> CheckTerritoryTransitionAsync(Guid gameId, Guid playerId, Position fromPosition, Position toPosition)
    {
        try
        {
            _logger.LogDebug("检测领地转换，玩家 {PlayerId}，从 ({FromX},{FromY}) 到 ({ToX},{ToY})", 
                playerId, fromPosition.X, fromPosition.Y, toPosition.X, toPosition.Y);

            var result = new TerritoryTransitionResult();

            // 检测起始位置的领地归属
            var previousOwnership = await CheckPositionTerritoryOwnershipAsync(gameId, fromPosition);
            
            // 检测目标位置的领地归属
            var currentOwnership = await CheckPositionTerritoryOwnershipAsync(gameId, toPosition);

            // 判断是否发生了领地转换
            if (previousOwnership?.OwnerId != currentOwnership?.OwnerId)
            {
                result.TerritoryChanged = true;
                result.PreviousOwnerId = previousOwnership?.OwnerId;
                result.CurrentOwnerId = currentOwnership?.OwnerId;

                // 获取玩家名称信息
                if (result.PreviousOwnerId.HasValue)
                {
                    result.PreviousOwnerName = await GetPlayerNameAsync(gameId, result.PreviousOwnerId.Value);
                }
                
                if (result.CurrentOwnerId.HasValue)
                {
                    result.CurrentOwnerName = await GetPlayerNameAsync(gameId, result.CurrentOwnerId.Value);
                }

                // 确定转换类型
                result.TransitionType = DetermineTransitionType(previousOwnership, currentOwnership);

                // 计算速度修正
                result.SpeedModifier = CalculateSpeedModifier(playerId, currentOwnership, result.TransitionType);

                _logger.LogDebug("检测到领地转换，玩家 {PlayerId}，转换类型: {TransitionType}，速度修正: {SpeedModifier}", 
                    playerId, result.TransitionType, result.SpeedModifier);
            }
            else
            {
                result.SpeedModifier = CalculateSpeedModifier(playerId, currentOwnership, TerritoryTransitionType.NoChange);
            }

            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "检测领地转换时发生错误，GameId: {GameId}, PlayerId: {PlayerId}", gameId, playerId);
            return new TerritoryTransitionResult { SpeedModifier = 1.0f };
        }
    }

    /// <summary>
    /// 检测轨迹预警
    /// 当敌方玩家接近自己的轨迹时发出预警，提醒玩家注意危险
    /// </summary>
    /// <param name="gameId">游戏标识</param>
    /// <param name="playerId">轨迹所有者</param>
    /// <param name="threatPlayerPosition">威胁玩家位置</param>
    /// <param name="warningDistance">预警距离，默认3像素</param>
    /// <returns>轨迹预警结果</returns>
    public async Task<TrailWarningResult> CheckTrailWarningAsync(Guid gameId, Guid playerId, Position threatPlayerPosition, float warningDistance = 3f)
    {
        try
        {
            _logger.LogDebug("检测轨迹预警，玩家 {PlayerId}，威胁位置: ({X},{Y})，预警距离: {Distance}", 
                playerId, threatPlayerPosition.X, threatPlayerPosition.Y, warningDistance);

            var result = new TrailWarningResult();

            // 获取目标玩家的当前轨迹
            var trailKey = $"game:{gameId}:player:{playerId}:trail";
            var trailData = await _redisService.ListRangeAsync(trailKey);

            if (trailData.Count < 2)
            {
                _logger.LogDebug("玩家 {PlayerId} 当前没有活跃轨迹", playerId);
                return result;
            }

            // 解析轨迹数据
            var trail = new List<Position>();
            foreach (var pointData in trailData)
            {
                var parts = pointData.Split(',');
                if (parts.Length >= 2 && 
                    float.TryParse(parts[0], out float x) && 
                    float.TryParse(parts[1], out float y))
                {
                    trail.Add(new Position { X = x, Y = y });
                }
            }

            var threats = new List<TrailThreat>();
            float minDistance = float.MaxValue;
            TrailThreat? immediateThreat = null;

            // 检查威胁位置与轨迹每个线段的距离
            for (int i = 0; i < trail.Count - 1; i++)
            {
                var segmentStart = trail[i];
                var segmentEnd = trail[i + 1];

                // 计算点到线段的最短距离
                var distance = CalculatePointToLineSegmentDistance(threatPlayerPosition, segmentStart, segmentEnd);
                var nearestPoint = FindNearestPointOnLineSegment(threatPlayerPosition, segmentStart, segmentEnd);

                if (distance <= warningDistance)
                {
                    // 计算威胁等级
                    var threatLevel = CalculateThreatLevel(distance, warningDistance);
                    
                    // 估算接触时间（简单估算，假设匀速移动）
                    var timeToContact = distance / 100f; // 假设平均速度为100像素/秒

                    var threat = new TrailThreat
                    {
                        ThreatPlayerId = playerId, // 这里需要传入威胁玩家的ID
                        ThreatPosition = threatPlayerPosition,
                        NearestTrailPoint = nearestPoint,
                        Distance = distance,
                        Level = threatLevel,
                        TimeToContact = timeToContact
                    };

                    threats.Add(threat);

                    if (distance < minDistance)
                    {
                        minDistance = distance;
                        immediateThreat = threat;
                    }

                    _logger.LogDebug("检测到轨迹威胁，距离: {Distance}，威胁等级: {Level}", distance, threatLevel);
                }
            }

            result.ShouldWarn = threats.Any();
            result.Threats = threats;
            result.ImmediateThreat = immediateThreat;
            result.MinimumDistance = minDistance == float.MaxValue ? 0 : minDistance;

            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "检测轨迹预警时发生错误，GameId: {GameId}, PlayerId: {PlayerId}", gameId, playerId);
            return new TrailWarningResult();
        }
    }

    /// <summary>
    /// 检测炸弹道具影响范围
    /// 检测炸弹道具爆炸范围内的所有轨迹和玩家，计算新领地区域
    /// </summary>
    /// <param name="gameId">游戏标识</param>
    /// <param name="explosionCenter">爆炸中心位置</param>
    /// <param name="explosionRadius">爆炸半径，默认30像素</param>
    /// <returns>爆炸影响检测结果</returns>
    public async Task<ExplosionCollisionResult> CheckBombExplosionAsync(Guid gameId, Position explosionCenter, float explosionRadius = 30f)
    {
        try
        {
            _logger.LogDebug("检测炸弹爆炸影响，中心: ({X},{Y})，半径: {Radius}", 
                explosionCenter.X, explosionCenter.Y, explosionRadius);

            var result = new ExplosionCollisionResult();

            // 获取所有玩家列表
            var playersKey = $"game:{gameId}:players";
            var allPlayers = await _redisService.GetSetMembersAsync(playersKey);

            var affectedPlayerTrails = new List<Guid>();
            var clearedTrailPoints = new List<Position>();

            // 检查每个玩家的轨迹是否受到爆炸影响
            foreach (var playerIdStr in allPlayers)
            {
                if (!Guid.TryParse(playerIdStr, out var playerId))
                    continue;

                // 获取玩家当前轨迹
                var trailKey = $"game:{gameId}:player:{playerId}:trail";
                var trailData = await _redisService.ListRangeAsync(trailKey);

                if (!trailData.Any()) continue;

                // 解析轨迹数据
                var trail = new List<Position>();
                foreach (var pointData in trailData)
                {
                    var parts = pointData.Split(',');
                    if (parts.Length >= 2 && 
                        float.TryParse(parts[0], out float x) && 
                        float.TryParse(parts[1], out float y))
                    {
                        var trailPoint = new Position { X = x, Y = y };
                        trail.Add(trailPoint);

                        // 检查轨迹点是否在爆炸范围内
                        var distance = CalculateDistance(explosionCenter, trailPoint);
                        if (distance <= explosionRadius)
                        {
                            clearedTrailPoints.Add(trailPoint);
                            if (!affectedPlayerTrails.Contains(playerId))
                            {
                                affectedPlayerTrails.Add(playerId);
                            }
                        }
                    }
                }
            }

            // 生成新的圆形领地边界
            var newTerritoryBoundary = GenerateCircularTerritory(explosionCenter, explosionRadius);
            
            // 计算新增领地面积
            var areaGained = CalculateCircularArea(explosionRadius);

            result.HasTargets = affectedPlayerTrails.Any() || clearedTrailPoints.Any();
            result.AffectedPlayerTrails = affectedPlayerTrails;
            result.ClearedTrailPoints = clearedTrailPoints;
            result.TerritoryAreaGained = areaGained;
            result.NewTerritoryBoundary = newTerritoryBoundary;

            _logger.LogDebug("炸弹爆炸影响检测完成，受影响玩家: {Count}，清除轨迹点: {Points}，新增面积: {Area}", 
                affectedPlayerTrails.Count, clearedTrailPoints.Count, areaGained);

            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "检测炸弹爆炸影响时发生错误，GameId: {GameId}", gameId);
            return new ExplosionCollisionResult();
        }
    }

    /// <summary>
    /// 生成圆形领地边界点
    /// 根据中心点和半径生成圆形边界的多边形近似
    /// </summary>
    private List<Position> GenerateCircularTerritory(Position center, float radius, int segments = 32)
    {
        var boundary = new List<Position>();
        var angleStep = 2 * Math.PI / segments;

        for (int i = 0; i < segments; i++)
        {
            var angle = i * angleStep;
            var x = center.X + radius * (float)Math.Cos(angle);
            var y = center.Y + radius * (float)Math.Sin(angle);
            boundary.Add(new Position { X = x, Y = y });
        }

        return boundary;
    }

    /// <summary>
    /// 计算圆形面积
    /// </summary>
    private decimal CalculateCircularArea(float radius)
    {
        return (decimal)(Math.PI * radius * radius);
    }

    /// <summary>
    /// 检测圈地闭合
    /// 检测玩家画线轨迹是否与自己的领地形成闭合回路，实现圈地功能
    /// </summary>
    /// <param name="gameId">游戏标识</param>
    /// <param name="playerId">玩家标识</param>
    /// <param name="currentTrail">当前画线轨迹</param>
    /// <param name="endPosition">结束位置</param>
    /// <returns>圈地闭合检测结果</returns>
    public async Task<EnclosureDetectionResult> CheckTerritoryEnclosureAsync(Guid gameId, Guid playerId, List<Position> currentTrail, Position endPosition)
    {
        try
        {
            _logger.LogDebug("检测圈地闭合，玩家 {PlayerId}，轨迹点数: {TrailCount}", playerId, currentTrail.Count);

            var result = new EnclosureDetectionResult();

            if (currentTrail.Count < 3)
            {
                result.InvalidReason = "轨迹点数不足，至少需要3个点";
                return result;
            }

            // 获取玩家当前领地
            var territoryKey = $"game:{gameId}:player:{playerId}:territory";
            var territoryData = await _redisService.ListRangeAsync(territoryKey);

            if (!territoryData.Any())
            {
                result.InvalidReason = "玩家没有现有领地，无法形成闭合";
                return result;
            }

            // 解析现有领地
            var existingTerritory = new List<Position>();
            foreach (var pointData in territoryData)
            {
                var parts = pointData.Split(',');
                if (parts.Length >= 2 && 
                    float.TryParse(parts[0], out float x) && 
                    float.TryParse(parts[1], out float y))
                {
                    existingTerritory.Add(new Position { X = x, Y = y });
                }
            }

            // 检查结束位置是否接触现有领地边界
            var connectionPoint = FindTerritoryConnectionPoint(endPosition, existingTerritory);
            if (connectionPoint == null)
            {
                result.InvalidReason = "结束位置未接触现有领地边界";
                return result;
            }

            // 构建完整的闭合区域
            var completeEnclosure = BuildCompleteEnclosure(currentTrail, endPosition, connectionPoint, existingTerritory);
            
            if (!IsValidEnclosure(completeEnclosure))
            {
                result.InvalidReason = "形成的区域不是有效的闭合多边形";
                return result;
            }

            // 检查画线长度限制
            var trailLength = CalculateTrailLength(currentTrail);
            var maxAllowedLength = await GetMaxTrailLengthAsync(gameId);
            
            if (trailLength > maxAllowedLength)
            {
                result.InvalidReason = $"画线长度超过限制 {trailLength:F1}/{maxAllowedLength:F1}";
                return result;
            }

            // 计算新增领地面积
            var newArea = CalculatePolygonArea(completeEnclosure);
            
            // 检查是否包围了其他玩家的领地
            var enclosedTerritories = await CheckEnclosedPlayerTerritories(gameId, playerId, completeEnclosure);

            result.IsEnclosed = true;
            result.EnclosedArea = completeEnclosure;
            result.AreaSize = newArea;
            result.EnclosedPlayerTerritories = enclosedTerritories;
            result.IsValidEnclosure = true;

            _logger.LogDebug("检测到有效圈地闭合，玩家 {PlayerId}，新增面积: {Area}，包围敌方领地: {Count}", 
                playerId, newArea, enclosedTerritories.Count);

            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "检测圈地闭合时发生错误，GameId: {GameId}, PlayerId: {PlayerId}", gameId, playerId);
            return new EnclosureDetectionResult { InvalidReason = "检测过程发生内部错误" };
        }
    }

    /// <summary>
    /// 寻找领地连接点
    /// 使用精确的几何算法找到结束位置与现有领地边界的最佳连接点
    /// </summary>
    private Position? FindTerritoryConnectionPoint(Position endPosition, List<Position> existingTerritory)
    {
        if (existingTerritory.Count < 2) return null;

        Position? bestConnectionPoint = null;
        float minDistance = float.MaxValue;
        const float CONNECTION_TOLERANCE = 8f; // 连接容差提升到8像素

        // 检查与每条边界线段的最近点
        for (int i = 0; i < existingTerritory.Count; i++)
        {
            var segmentStart = existingTerritory[i];
            var segmentEnd = existingTerritory[(i + 1) % existingTerritory.Count];
            
            // 计算点到线段的最近点和距离
            var nearestPoint = FindNearestPointOnLineSegment(endPosition, segmentStart, segmentEnd);
            var distance = CalculateDistance(endPosition, nearestPoint);
            
            if (distance <= CONNECTION_TOLERANCE && distance < minDistance)
            {
                minDistance = distance;
                bestConnectionPoint = nearestPoint;
            }
        }

        // 如果没有找到线段连接点，检查与顶点的直接连接
        if (bestConnectionPoint == null)
        {
            foreach (var vertex in existingTerritory)
            {
                var distance = CalculateDistance(endPosition, vertex);
                if (distance <= CONNECTION_TOLERANCE * 1.5f && distance < minDistance)
                {
                    minDistance = distance;
                    bestConnectionPoint = vertex;
                }
            }
        }

        return bestConnectionPoint;
    }

    /// <summary>
    /// 构建完整的闭合区域
    /// 使用精确的几何算法将当前轨迹与现有领地连接形成有效的多边形
    /// </summary>
    private List<Position> BuildCompleteEnclosure(List<Position> currentTrail, Position endPosition, 
        Position connectionPoint, List<Position> existingTerritory)
    {
        var completeEnclosure = new List<Position>();

        // 1. 添加轨迹起点（如果不在现有领地边界上）
        var trailStart = currentTrail[0];
        if (!IsPointOnTerritoryBoundary(trailStart, existingTerritory))
        {
            // 找到轨迹起点在现有领地上的连接点
            var startConnectionPoint = FindTerritoryConnectionPoint(trailStart, existingTerritory);
            if (startConnectionPoint != null)
            {
                completeEnclosure.Add(startConnectionPoint);
            }
        }
        else
        {
            completeEnclosure.Add(trailStart);
        }

        // 2. 添加完整的当前轨迹路径
        for (int i = 1; i < currentTrail.Count; i++)
        {
            completeEnclosure.Add(currentTrail[i]);
        }

        // 3. 添加结束位置（如果与轨迹最后一点不同）
        var lastTrailPoint = currentTrail[currentTrail.Count - 1];
        if (CalculateDistance(lastTrailPoint, endPosition) > 1f)
        {
            completeEnclosure.Add(endPosition);
        }

        // 4. 添加连接点
        if (CalculateDistance(endPosition, connectionPoint) > 1f)
        {
            completeEnclosure.Add(connectionPoint);
        }

        // 5. 找到连接点在现有领地边界上的位置
        var connectionSegmentIndex = FindConnectionSegmentIndex(connectionPoint, existingTerritory);
        if (connectionSegmentIndex >= 0)
        {
            // 沿着领地边界回到起始连接点
            var boundaryPath = ExtractBoundaryPath(existingTerritory, connectionSegmentIndex, trailStart);
            completeEnclosure.AddRange(boundaryPath);
        }

        // 6. 移除重复点和共线点
        completeEnclosure = RemoveDuplicateAndCollinearPoints(completeEnclosure);

        return completeEnclosure;
    }

    /// <summary>
    /// 检查点是否在领地边界上
    /// </summary>
    private bool IsPointOnTerritoryBoundary(Position point, List<Position> territory)
    {
        const float BOUNDARY_TOLERANCE = 3f;

        for (int i = 0; i < territory.Count; i++)
        {
            var segmentStart = territory[i];
            var segmentEnd = territory[(i + 1) % territory.Count];
            
            var distance = CalculatePointToLineSegmentDistance(point, segmentStart, segmentEnd);
            if (distance <= BOUNDARY_TOLERANCE)
            {
                return true;
            }
        }

        return false;
    }

    /// <summary>
    /// 找到连接点所在的边界线段索引
    /// </summary>
    private int FindConnectionSegmentIndex(Position connectionPoint, List<Position> territory)
    {
        const float SEGMENT_TOLERANCE = 2f;

        for (int i = 0; i < territory.Count; i++)
        {
            var segmentStart = territory[i];
            var segmentEnd = territory[(i + 1) % territory.Count];
            
            var distance = CalculatePointToLineSegmentDistance(connectionPoint, segmentStart, segmentEnd);
            if (distance <= SEGMENT_TOLERANCE)
            {
                return i;
            }
        }

        return -1;
    }

    /// <summary>
    /// 提取边界路径
    /// 从连接点沿边界提取到起始点的路径
    /// </summary>
    private List<Position> ExtractBoundaryPath(List<Position> territory, int startSegmentIndex, Position targetStart)
    {
        var boundaryPath = new List<Position>();
        
        // 找到最接近目标起始点的领地顶点
        int targetVertexIndex = FindNearestBoundaryPointIndex(targetStart, territory);
        
        if (targetVertexIndex < 0) return boundaryPath;

        // 从连接线段的结束点开始
        int currentIndex = (startSegmentIndex + 1) % territory.Count;
        
        // 沿着边界路径添加点，直到到达目标顶点
        while (currentIndex != targetVertexIndex)
        {
            boundaryPath.Add(territory[currentIndex]);
            currentIndex = (currentIndex + 1) % territory.Count;
            
            // 防止无限循环
            if (boundaryPath.Count > territory.Count)
                break;
        }

        return boundaryPath;
    }

    /// <summary>
    /// 移除重复点和共线点
    /// 优化多边形结构，提高计算效率
    /// </summary>
    private List<Position> RemoveDuplicateAndCollinearPoints(List<Position> points)
    {
        if (points.Count < 3) return points;

        var optimized = new List<Position>();
        const float DUPLICATE_TOLERANCE = 1f;
        const float COLLINEAR_TOLERANCE = 0.1f;

        for (int i = 0; i < points.Count; i++)
        {
            var current = points[i];
            var next = points[(i + 1) % points.Count];
            var prev = points[(i - 1 + points.Count) % points.Count];

            // 跳过重复点
            if (optimized.Count > 0 && CalculateDistance(current, optimized[optimized.Count - 1]) < DUPLICATE_TOLERANCE)
                continue;

            // 跳过共线点
            if (optimized.Count > 0)
            {
                var crossProduct = CalculateCrossProduct(prev, current, next);
                if (Math.Abs(crossProduct) < COLLINEAR_TOLERANCE)
                    continue;
            }

            optimized.Add(current);
        }

        return optimized.Count >= 3 ? optimized : points;
    }

    /// <summary>
    /// 计算三点的叉积（用于检测共线性）
    /// </summary>
    private float CalculateCrossProduct(Position a, Position b, Position c)
    {
        return (b.X - a.X) * (c.Y - a.Y) - (b.Y - a.Y) * (c.X - a.X);
    }

    /// <summary>
    /// 检查是否是有效的闭合区域
    /// 使用复杂的几何验证确保多边形的有效性
    /// </summary>
    private bool IsValidEnclosure(List<Position> enclosure)
    {
        if (enclosure.Count < 3) return false;

        // 1. 检查多边形是否自相交
        if (HasSelfIntersection(enclosure)) return false;

        // 2. 检查面积是否足够大（避免无意义的小区域）
        var area = CalculatePolygonArea(enclosure);
        const decimal MIN_AREA = 100m; // 最小100平方像素
        if (area < MIN_AREA) return false;

        // 3. 检查多边形的凸凹性和复杂度
        if (IsPolygonTooComplex(enclosure)) return false;

        // 4. 检查边长是否合理（避免过短或过长的边）
        if (!AreEdgeLengthsReasonable(enclosure)) return false;

        return true;
    }

    /// <summary>
    /// 检查多边形是否存在自相交
    /// 使用改进的线段相交算法
    /// </summary>
    private bool HasSelfIntersection(List<Position> polygon)
    {
        int n = polygon.Count;
        
        for (int i = 0; i < n; i++)
        {
            var segment1Start = polygon[i];
            var segment1End = polygon[(i + 1) % n];
            
            // 检查与其他非相邻线段的交点
            for (int j = i + 2; j < n; j++)
            {
                // 避免检查最后一条边与第一条边的交点（这是合法的闭合）
                if (i == 0 && j == n - 1) continue;
                
                var segment2Start = polygon[j];
                var segment2End = polygon[(j + 1) % n];
                
                if (DoLineSegmentsIntersect(segment1Start, segment1End, segment2Start, segment2End))
                {
                    return true;
                }
            }
        }
        
        return false;
    }

    /// <summary>
    /// 精确的线段相交检测
    /// 使用定向面积测试
    /// </summary>
    private bool DoLineSegmentsIntersect(Position p1, Position p2, Position p3, Position p4)
    {
        var d1 = GetOrientation(p3, p4, p1);
        var d2 = GetOrientation(p3, p4, p2);
        var d3 = GetOrientation(p1, p2, p3);
        var d4 = GetOrientation(p1, p2, p4);
        
        if (((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) &&
            ((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0)))
        {
            return true; // 一般情况：线段相交
        }
        
        // 检查共线和重叠的特殊情况
        if (d1 == 0 && IsPointOnSegment(p1, p3, p4)) return true;
        if (d2 == 0 && IsPointOnSegment(p2, p3, p4)) return true;
        if (d3 == 0 && IsPointOnSegment(p3, p1, p2)) return true;
        if (d4 == 0 && IsPointOnSegment(p4, p1, p2)) return true;
        
        return false;
    }

    /// <summary>
    /// 计算定向面积（叉积）
    /// </summary>
    private float GetOrientation(Position a, Position b, Position c)
    {
        return (b.X - a.X) * (c.Y - a.Y) - (b.Y - a.Y) * (c.X - a.X);
    }

    /// <summary>
    /// 检查点是否在线段上
    /// </summary>
    private bool IsPointOnSegment(Position point, Position segmentStart, Position segmentEnd)
    {
        const float EPSILON = 1e-6f;
        
        // 检查点是否在线段的边界框内
        if (point.X < Math.Min(segmentStart.X, segmentEnd.X) - EPSILON ||
            point.X > Math.Max(segmentStart.X, segmentEnd.X) + EPSILON ||
            point.Y < Math.Min(segmentStart.Y, segmentEnd.Y) - EPSILON ||
            point.Y > Math.Max(segmentStart.Y, segmentEnd.Y) + EPSILON)
        {
            return false;
        }
        
        // 检查点是否在直线上
        var crossProduct = GetOrientation(segmentStart, segmentEnd, point);
        return Math.Abs(crossProduct) < EPSILON;
    }

    /// <summary>
    /// 检查多边形是否过于复杂
    /// </summary>
    private bool IsPolygonTooComplex(List<Position> polygon)
    {
        // 限制顶点数量
        if (polygon.Count > 100) return true;

        // 检查尖锐角度的数量
        int sharpAngleCount = 0;
        for (int i = 0; i < polygon.Count; i++)
        {
            var prev = polygon[(i - 1 + polygon.Count) % polygon.Count];
            var current = polygon[i];
            var next = polygon[(i + 1) % polygon.Count];
            
            var angle = CalculateAngle(prev, current, next);
            if (angle < 15 || angle > 165) // 过于尖锐或平直的角
            {
                sharpAngleCount++;
            }
        }
        
        // 如果超过一半的角都是尖锐角，认为过于复杂
        return sharpAngleCount > polygon.Count / 2;
    }

    /// <summary>
    /// 计算三点形成的角度
    /// </summary>
    private double CalculateAngle(Position a, Position b, Position c)
    {
        var ba = new Vector2(a.X - b.X, a.Y - b.Y);
        var bc = new Vector2(c.X - b.X, c.Y - b.Y);
        
        var dot = Vector2.Dot(ba, bc);
        var magnitudes = ba.Length() * bc.Length();
        
        if (magnitudes == 0) return 0;
        
        var cosAngle = dot / magnitudes;
        cosAngle = Math.Max(-1, Math.Min(1, cosAngle)); // 限制在[-1, 1]范围内
        
        return Math.Acos(cosAngle) * 180.0 / Math.PI;
    }

    /// <summary>
    /// 检查边长是否合理
    /// </summary>
    private bool AreEdgeLengthsReasonable(List<Position> polygon)
    {
        const float MIN_EDGE_LENGTH = 3f;
        const float MAX_EDGE_LENGTH = 500f;
        
        for (int i = 0; i < polygon.Count; i++)
        {
            var current = polygon[i];
            var next = polygon[(i + 1) % polygon.Count];
            var edgeLength = CalculateDistance(current, next);
            
            if (edgeLength < MIN_EDGE_LENGTH || edgeLength > MAX_EDGE_LENGTH)
            {
                return false;
            }
        }
        
        return true;
    }

    /// <summary>
    /// 计算轨迹长度
    /// </summary>
    private float CalculateTrailLength(List<Position> trail)
    {
        if (trail.Count < 2) return 0;

        float totalLength = 0;
        for (int i = 0; i < trail.Count - 1; i++)
        {
            totalLength += CalculateDistance(trail[i], trail[i + 1]);
        }

        return totalLength;
    }

    /// <summary>
    /// 获取最大允许轨迹长度
    /// </summary>
    private async Task<float> GetMaxTrailLengthAsync(Guid gameId)
    {
        try
        {
            var gameConfigKey = $"game:{gameId}:config";
            var gameConfig = await _redisService.GetHashAllAsync(gameConfigKey);

            var mapWidth = float.Parse(gameConfig.GetValueOrDefault("map_width", "1000"));
            var mapHeight = float.Parse(gameConfig.GetValueOrDefault("map_height", "1000"));
            
            // 最大画线长度为地图对角线的1.5倍
            var diagonal = (float)Math.Sqrt(mapWidth * mapWidth + mapHeight * mapHeight);
            return diagonal * 1.5f;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取最大轨迹长度时发生错误");
            return 1500f; // 默认值
        }
    }

    /// <summary>
    /// 检查被包围的敌方玩家领地
    /// </summary>
    private async Task<List<Guid>> CheckEnclosedPlayerTerritories(Guid gameId, Guid currentPlayerId, List<Position> enclosure)
    {
        var enclosedTerritories = new List<Guid>();

        try
        {
            var playersKey = $"game:{gameId}:players";
            var allPlayers = await _redisService.GetSetMembersAsync(playersKey);

            foreach (var playerIdStr in allPlayers)
            {
                if (!Guid.TryParse(playerIdStr, out var playerId) || playerId == currentPlayerId)
                    continue;

                // 获取其他玩家的领地
                var territoryKey = $"game:{gameId}:player:{playerId}:territory";
                var territoryData = await _redisService.ListRangeAsync(territoryKey);

                if (!territoryData.Any()) continue;

                // 解析玩家领地
                var playerTerritory = new List<Position>();
                foreach (var pointData in territoryData)
                {
                    var parts = pointData.Split(',');
                    if (parts.Length >= 2 && 
                        float.TryParse(parts[0], out float x) && 
                        float.TryParse(parts[1], out float y))
                    {
                        playerTerritory.Add(new Position { X = x, Y = y });
                    }
                }

                // 检查该玩家的领地是否被完全包围
                if (IsTerritoryCompletelyEnclosed(playerTerritory, enclosure))
                {
                    enclosedTerritories.Add(playerId);
                }
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "检查被包围领地时发生错误");
        }

        return enclosedTerritories;
    }

    /// <summary>
    /// 查找边界点的最近索引
    /// </summary>
    private int FindNearestBoundaryPointIndex(Position point, List<Position> boundary)
    {
        int nearestIndex = -1;
        float minDistance = float.MaxValue;

        for (int i = 0; i < boundary.Count; i++)
        {
            var distance = CalculateDistance(point, boundary[i]);
            if (distance < minDistance)
            {
                minDistance = distance;
                nearestIndex = i;
            }
        }

        return nearestIndex;
    }

    /// <summary>
    /// 检查领地是否被完全包围
    /// </summary>
    private bool IsTerritoryCompletelyEnclosed(List<Position> territory, List<Position> enclosure)
    {
        if (territory.Count < 3 || enclosure.Count < 3) return false;

        // 检查领地的所有点是否都在包围区域内
        foreach (var point in territory)
        {
            if (!IsPointInPolygon(point, enclosure))
            {
                return false;
            }
        }

        return true;
    }

    /// <summary>
    /// 检测地图缩圈影响
    /// 检测地图缩圈时哪些玩家的领地会受到影响，计算损失的领地面积
    /// </summary>
    /// <param name="gameId">游戏标识</param>
    /// <param name="newMapRadius">新的地图半径</param>
    /// <returns>地图缩圈影响结果</returns>
    public async Task<MapShrinkCollisionResult> CheckMapShrinkCollisionAsync(Guid gameId, float newMapRadius)
    {
        try
        {
            _logger.LogDebug("检测地图缩圈影响，新半径: {Radius}", newMapRadius);

            var result = new MapShrinkCollisionResult();

            // 获取地图配置
            var gameConfigKey = $"game:{gameId}:config";
            var gameConfig = await _redisService.GetHashAllAsync(gameConfigKey);

            if (!gameConfig.Any())
            {
                _logger.LogWarning("游戏 {GameId} 配置不存在", gameId);
                return result;
            }

            // 获取地图中心点
            var mapWidth = float.Parse(gameConfig.GetValueOrDefault("map_width", "1000"));
            var mapHeight = float.Parse(gameConfig.GetValueOrDefault("map_height", "1000"));
            var mapCenter = new Position
            {
                X = mapWidth / 2f,
                Y = mapHeight / 2f
            };

            result.NewMapRadius = newMapRadius;
            result.MapCenter = mapCenter;

            // 获取所有玩家
            var playersKey = $"game:{gameId}:players";
            var allPlayers = await _redisService.GetSetMembersAsync(playersKey);

            var territoryLosses = new List<PlayerTerritoryLoss>();

            foreach (var playerIdStr in allPlayers)
            {
                if (!Guid.TryParse(playerIdStr, out var playerId))
                    continue;

                // 获取玩家当前领地
                var territoryKey = $"game:{gameId}:player:{playerId}:territory";
                var territoryData = await _redisService.ListRangeAsync(territoryKey);

                if (!territoryData.Any()) continue;

                // 解析玩家领地
                var playerTerritory = new List<Position>();
                foreach (var pointData in territoryData)
                {
                    var parts = pointData.Split(',');
                    if (parts.Length >= 2 && 
                        float.TryParse(parts[0], out float x) && 
                        float.TryParse(parts[1], out float y))
                    {
                        playerTerritory.Add(new Position { X = x, Y = y });
                    }
                }

                if (playerTerritory.Count < 3) continue;

                // 计算原始面积
                var originalArea = CalculatePolygonArea(playerTerritory);

                // 裁剪领地到新的地图范围内
                var clippedTerritory = ClipTerritoryToCircle(playerTerritory, mapCenter, newMapRadius);
                var remainingArea = clippedTerritory.Any() ? CalculatePolygonArea(clippedTerritory) : 0m;

                var areaLost = originalArea - remainingArea;

                if (areaLost > 0)
                {
                    // 获取玩家名称
                    var playerName = await GetPlayerNameAsync(gameId, playerId) ?? playerId.ToString()[..8];

                    var territoryLoss = new PlayerTerritoryLoss
                    {
                        PlayerId = playerId,
                        PlayerName = playerName,
                        AreaLost = areaLost,
                        RemainingArea = remainingArea,
                        LostTerritoryBoundary = CalculateLostTerritoryBoundary(playerTerritory, clippedTerritory)
                    };

                    territoryLosses.Add(territoryLoss);

                    _logger.LogDebug("玩家 {PlayerId} ({PlayerName}) 因地图缩圈损失面积: {AreaLost}，剩余面积: {RemainingArea}", 
                        playerId, playerName, areaLost, remainingArea);
                }
            }

            result.HasAffectedTerritories = territoryLosses.Any();
            result.TerritoryLosses = territoryLosses;
            result.TotalAffectedPlayers = territoryLosses.Count;

            _logger.LogDebug("地图缩圈影响检测完成，受影响玩家: {Count}，总损失面积: {TotalLoss}", 
                territoryLosses.Count, territoryLosses.Sum(t => t.AreaLost));

            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "检测地图缩圈影响时发生错误，GameId: {GameId}", gameId);
            return new MapShrinkCollisionResult();
        }
    }

    /// <summary>
    /// 计算多边形面积
    /// 使用鞋带公式（Shoelace formula）计算多边形面积
    /// </summary>
    private decimal CalculatePolygonArea(List<Position> polygon)
    {
        if (polygon.Count < 3) return 0;

        double area = 0;
        int n = polygon.Count;

        for (int i = 0; i < n; i++)
        {
            int j = (i + 1) % n;
            area += polygon[i].X * polygon[j].Y;
            area -= polygon[j].X * polygon[i].Y;
        }

        return (decimal)(Math.Abs(area) / 2.0);
    }

    /// <summary>
    /// 将领地裁剪到圆形区域内
    /// 使用改进的Sutherland-Hodgman多边形裁剪算法
    /// </summary>
    private List<Position> ClipTerritoryToCircle(List<Position> territory, Position center, float radius)
    {
        if (territory.Count < 3) return new List<Position>();

        var clipped = new List<Position>(territory);
        var result = new List<Position>();

        // 使用Sutherland-Hodgman算法的圆形版本
        for (int i = 0; i < clipped.Count; i++)
        {
            var current = clipped[i];
            var next = clipped[(i + 1) % clipped.Count];

            var currentDistance = CalculateDistance(current, center);
            var nextDistance = CalculateDistance(next, center);

            var currentInside = currentDistance <= radius;
            var nextInside = nextDistance <= radius;

            if (currentInside && nextInside)
            {
                // 两点都在内部，添加next点
                if (!result.Contains(next))
                    result.Add(next);
            }
            else if (currentInside && !nextInside)
            {
                // 从内部到外部，添加交点
                var intersection = CalculateCircleLineIntersection(current, next, center, radius);
                if (intersection != null && !result.Contains(intersection))
                    result.Add(intersection);
            }
            else if (!currentInside && nextInside)
            {
                // 从外部到内部，添加交点和next点
                var intersection = CalculateCircleLineIntersection(current, next, center, radius);
                if (intersection != null && !result.Contains(intersection))
                    result.Add(intersection);
                if (!result.Contains(next))
                    result.Add(next);
            }
            // 两点都在外部，不添加任何点
        }

        return result.Count >= 3 ? result : new List<Position>();
    }

    /// <summary>
    /// 计算线段与圆的交点
    /// </summary>
    private Position? CalculateCircleLineIntersection(Position p1, Position p2, Position center, float radius)
    {
        var dx = p2.X - p1.X;
        var dy = p2.Y - p1.Y;
        var fx = p1.X - center.X;
        var fy = p1.Y - center.Y;

        var a = dx * dx + dy * dy;
        var b = 2 * (fx * dx + fy * dy);
        var c = (fx * fx + fy * fy) - radius * radius;

        var discriminant = b * b - 4 * a * c;

        if (discriminant < 0) return null; // 无交点

        var sqrt_discriminant = Math.Sqrt(discriminant);
        var t1 = (-b - sqrt_discriminant) / (2 * a);
        var t2 = (-b + sqrt_discriminant) / (2 * a);

        // 选择在线段范围内的交点
        var t = (t1 >= 0 && t1 <= 1) ? t1 : 
                (t2 >= 0 && t2 <= 1) ? t2 : -1;

        if (t < 0) return null;

        return new Position
        {
            X = p1.X + (float)(t * dx),
            Y = p1.Y + (float)(t * dy)
        };
    }

    /// <summary>
    /// 计算丢失的领地边界
    /// 计算原始领地与裁剪后领地的差集边界
    /// </summary>
    private List<Position> CalculateLostTerritoryBoundary(List<Position> originalTerritory, List<Position> clippedTerritory)
    {
        // 简化实现：返回被裁剪掉的点
        var lostBoundary = new List<Position>();

        foreach (var point in originalTerritory)
        {
            bool isInClipped = clippedTerritory.Any(cp => 
                Math.Abs(cp.X - point.X) < 1f && Math.Abs(cp.Y - point.Y) < 1f);

            if (!isInClipped)
            {
                lostBoundary.Add(point);
            }
        }

        return lostBoundary;
    }

    /// <summary>
    /// 批量碰撞检测优化
    /// 一次性检测多个玩家的移动碰撞，提高服务器性能，减少Redis查询次数
    /// </summary>
    /// <param name="gameId">游戏标识</param>
    /// <param name="playerMovements">玩家移动列表</param>
    /// <returns>批量碰撞检测结果</returns>
    public async Task<BatchCollisionResult> CheckBatchPlayerMovementsAsync(Guid gameId, List<PlayerMovement> playerMovements)
    {
        try
        {
            _logger.LogDebug("开始批量碰撞检测，玩家数量: {Count}", playerMovements.Count);

            var result = new BatchCollisionResult();
            var results = new List<PlayerCollisionResult>();
            var errors = new List<string>();

            // 预加载游戏数据以减少Redis查询
            var gameData = await PreloadGameDataForBatchProcessing(gameId);

            if (gameData == null)
            {
                errors.Add($"无法加载游戏 {gameId} 的数据");
                result.Errors = errors;
                return result;
            }

            // 并发处理所有玩家移动
            var tasks = playerMovements.Select(async movement =>
            {
                try
                {
                    var playerResult = new PlayerCollisionResult
                    {
                        PlayerId = movement.PlayerId,
                        ValidPosition = movement.ToPosition
                    };

                    var collisions = new List<CollisionDetail>();

                    // 1. 检查边界碰撞
                    var boundaryResult = await CheckMapBoundaryAsync(gameId, movement.ToPosition);
                    if (boundaryResult.IsOutOfBounds)
                    {
                        collisions.Add(new CollisionDetail
                        {
                            Category = CollisionCategory.BoundaryHit,
                            CollisionPoint = movement.ToPosition,
                            Description = "超出地图边界"
                        });
                        playerResult.ValidPosition = boundaryResult.ValidPosition;
                    }

                    // 2. 检查轨迹碰撞
                    var trailResult = await CheckTrailCollisionAsync(gameId, movement.PlayerId, 
                        movement.FromPosition, movement.ToPosition, movement.IsDrawing);
                    
                    if (trailResult.HasCollision)
                    {
                        collisions.Add(new CollisionDetail
                        {
                            Category = CollisionCategory.TrailCollision,
                            CollisionPoint = trailResult.CollisionPoint,
                            OtherPlayerId = trailResult.CollidedWithPlayerId,
                            Description = $"轨迹碰撞：{trailResult.CollisionType}"
                        });

                        if (trailResult.IsDeadly)
                        {
                            playerResult.ShouldDie = true;
                            playerResult.DeathReason = $"被{trailResult.CollisionType}截断";
                        }
                    }

                    // 3. 检查道具拾取
                    var powerUpResult = await CheckPowerUpPickupAsync(gameId, movement.PlayerId, movement.ToPosition);
                    if (powerUpResult.CanPickup && powerUpResult.ClosestPowerUp != null)
                    {
                        collisions.Add(new CollisionDetail
                        {
                            Category = CollisionCategory.PowerUpPickup,
                            CollisionPoint = powerUpResult.ClosestPowerUp.Position,
                            Description = $"拾取道具：{powerUpResult.ClosestPowerUp.Type}",
                            Properties = new Dictionary<string, object>
                            {
                                ["PowerUpId"] = powerUpResult.ClosestPowerUp.Id,
                                ["PowerUpType"] = powerUpResult.ClosestPowerUp.Type.ToString()
                            }
                        });
                    }

                    // 4. 检查领地转换
                    var territoryResult = await CheckTerritoryTransitionAsync(gameId, movement.PlayerId, 
                        movement.FromPosition, movement.ToPosition);
                    
                    if (territoryResult.TerritoryChanged)
                    {
                        collisions.Add(new CollisionDetail
                        {
                            Category = CollisionCategory.TerritoryTransition,
                            CollisionPoint = movement.ToPosition,
                            OtherPlayerId = territoryResult.CurrentOwnerId,
                            Description = $"领地转换：{territoryResult.TransitionType}",
                            Properties = new Dictionary<string, object>
                            {
                                ["SpeedModifier"] = territoryResult.SpeedModifier,
                                ["TransitionType"] = territoryResult.TransitionType.ToString()
                            }
                        });
                    }

                    playerResult.HasCollision = collisions.Any();
                    playerResult.Collisions = collisions;

                    return playerResult;
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "处理玩家 {PlayerId} 移动时发生错误", movement.PlayerId);
                    return new PlayerCollisionResult
                    {
                        PlayerId = movement.PlayerId,
                        HasCollision = false,
                        ValidPosition = movement.FromPosition // 出错时保持原位置
                    };
                }
            });

            // 等待所有任务完成
            results.AddRange(await Task.WhenAll(tasks));

            result.Results = results;
            result.ProcessedMovements = playerMovements.Count;
            result.TotalCollisions = results.Count(r => r.HasCollision);
            result.Errors = errors;

            _logger.LogDebug("批量碰撞检测完成，处理移动: {Processed}，检测到碰撞: {Collisions}", 
                result.ProcessedMovements, result.TotalCollisions);

            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "批量碰撞检测时发生错误，GameId: {GameId}", gameId);
            return new BatchCollisionResult 
            { 
                Errors = new List<string> { "批量处理过程发生内部错误" } 
            };
        }
    }

    /// <summary>
    /// 预加载游戏数据用于批量处理
    /// 使用智能缓存策略，预加载所有必要的游戏数据，大幅减少Redis查询
    /// </summary>
    private async Task<GameDataCache?> PreloadGameDataForBatchProcessing(Guid gameId)
    {
        try
        {
            var gameData = new GameDataCache { GameId = gameId };

            // 并发加载多个数据源
            var tasks = new List<Task>();

            // 1. 加载游戏配置
            tasks.Add(Task.Run(async () =>
            {
                var gameConfigKey = $"game:{gameId}:config";
                gameData.GameConfig = await _redisService.GetHashAllAsync(gameConfigKey);
            }));

            // 2. 加载玩家列表
            tasks.Add(Task.Run(async () =>
            {
                var playersKey = $"game:{gameId}:players";
                gameData.PlayerIds = await _redisService.GetSetMembersAsync(playersKey);
            }));

            // 3. 加载所有玩家的轨迹数据
            tasks.Add(Task.Run(async () =>
            {
                var playersKey = $"game:{gameId}:players";
                var playerIds = await _redisService.GetSetMembersAsync(playersKey);
                
                var trailTasks = playerIds.Select(async playerIdStr =>
                {
                    if (Guid.TryParse(playerIdStr, out var playerId))
                    {
                        var trailKey = $"game:{gameId}:player:{playerId}:trail";
                        var trailData = await _redisService.ListRangeAsync(trailKey);
                        return new KeyValuePair<Guid, List<Position>>(playerId, ParsePositionList(trailData));
                    }
                    return new KeyValuePair<Guid, List<Position>>(Guid.Empty, new List<Position>());
                });

                var trailResults = await Task.WhenAll(trailTasks);
                gameData.PlayerTrails = trailResults
                    .Where(kvp => kvp.Key != Guid.Empty)
                    .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
            }));

            // 4. 加载所有玩家的领地数据
            tasks.Add(Task.Run(async () =>
            {
                var playersKey = $"game:{gameId}:players";
                var playerIds = await _redisService.GetSetMembersAsync(playersKey);
                
                var territoryTasks = playerIds.Select(async playerIdStr =>
                {
                    if (Guid.TryParse(playerIdStr, out var playerId))
                    {
                        var territoryKey = $"game:{gameId}:player:{playerId}:territory";
                        var territoryData = await _redisService.ListRangeAsync(territoryKey);
                        return new KeyValuePair<Guid, List<Position>>(playerId, ParsePositionList(territoryData));
                    }
                    return new KeyValuePair<Guid, List<Position>>(Guid.Empty, new List<Position>());
                });

                var territoryResults = await Task.WhenAll(territoryTasks);
                gameData.PlayerTerritories = territoryResults
                    .Where(kvp => kvp.Key != Guid.Empty)
                    .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
            }));

            // 5. 加载所有玩家状态
            tasks.Add(Task.Run(async () =>
            {
                var playersKey = $"game:{gameId}:players";
                var playerIds = await _redisService.GetSetMembersAsync(playersKey);
                
                var stateTasks = playerIds.Select(async playerIdStr =>
                {
                    if (Guid.TryParse(playerIdStr, out var playerId))
                    {
                        var stateKey = $"game:{gameId}:player:{playerId}";
                        var stateData = await _redisService.GetHashAllAsync(stateKey);
                        return new KeyValuePair<Guid, Dictionary<string, string>>(playerId, stateData);
                    }
                    return new KeyValuePair<Guid, Dictionary<string, string>>(Guid.Empty, new Dictionary<string, string>());
                });

                var stateResults = await Task.WhenAll(stateTasks);
                gameData.PlayerStates = stateResults
                    .Where(kvp => kvp.Key != Guid.Empty)
                    .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
            }));

            // 6. 加载道具数据
            tasks.Add(Task.Run(async () =>
            {
                var powerUpsKey = $"game:{gameId}:powerups";
                var powerUpIds = await _redisService.GetSetMembersAsync(powerUpsKey);
                
                var powerUpTasks = powerUpIds.Select(async powerUpIdStr =>
                {
                    if (Guid.TryParse(powerUpIdStr, out var powerUpId))
                    {
                        var powerUpKey = $"game:{gameId}:powerup:{powerUpId}";
                        var powerUpData = await _redisService.GetHashAllAsync(powerUpKey);
                        var powerUp = ParsePickupablePowerUp(powerUpId, powerUpData);
                        return powerUp;
                    }
                    return null;
                });

                var powerUpResults = await Task.WhenAll(powerUpTasks);
                gameData.ActivePowerUps = powerUpResults.Where(p => p != null).ToList()!;
            }));

            // 7. 加载障碍物数据
            tasks.Add(Task.Run(async () =>
            {
                var obstaclesKey = $"game:{gameId}:obstacles";
                var obstacleIds = await _redisService.GetSetMembersAsync(obstaclesKey);
                
                var obstacleTasks = obstacleIds.Select(async obstacleIdStr =>
                {
                    if (Guid.TryParse(obstacleIdStr, out var obstacleId))
                    {
                        var obstacleKey = $"game:{gameId}:obstacle:{obstacleId}";
                        var obstacleData = await _redisService.GetHashAllAsync(obstacleKey);
                        return ParseMapObstacle(obstacleId, obstacleData);
                    }
                    return null;
                });

                var obstacleResults = await Task.WhenAll(obstacleTasks);
                gameData.MapObstacles = obstacleResults.Where(o => o != null).ToList()!;
            }));

            // 等待所有数据加载完成
            await Task.WhenAll(tasks);

            return gameData;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "预加载游戏数据时发生错误，GameId: {GameId}", gameId);
            return null;
        }
    }

    /// <summary>
    /// 解析位置列表字符串
    /// </summary>
    private List<Position> ParsePositionList(List<string> positionData)
    {
        var positions = new List<Position>();
        
        foreach (var pointData in positionData)
        {
            var parts = pointData.Split(',');
            if (parts.Length >= 2 && 
                float.TryParse(parts[0], out float x) && 
                float.TryParse(parts[1], out float y))
            {
                positions.Add(new Position { X = x, Y = y });
            }
        }
        
        return positions;
    }

    /// <summary>
    /// 增强的游戏数据缓存类
    /// 预加载所有批量处理需要的数据，避免重复Redis查询
    /// </summary>
    private class GameDataCache
    {
        public Guid GameId { get; set; }
        public Dictionary<string, string> GameConfig { get; set; } = new();
        public HashSet<string> PlayerIds { get; set; } = new();
        public Dictionary<Guid, List<Position>> PlayerTrails { get; set; } = new();
        public Dictionary<Guid, List<Position>> PlayerTerritories { get; set; } = new();
        public Dictionary<Guid, Dictionary<string, string>> PlayerStates { get; set; } = new();
        public List<PickupablePowerUp> ActivePowerUps { get; set; } = new();
        public List<MapObstacle> MapObstacles { get; set; } = new();
    }
}
